using System;
using System.Collections.Generic;
using System.Text;
using Oracle.ManagedDataAccess.Client;
using Oracle.ManagedDataAccess.Types;
using OracleInternal.Common;

namespace OracleInternal.BinXml
{
	internal class ObxmlDecoder : ObxmlDecodeContext, IDisposable
	{
		private bool m_Disposed;

		private ObxmlDecodeState m_DecodeState;

		private ObxmlInstruction m_Instruction;

		private int DefaultDecodeBufferLength = 100;

		internal static Dictionary<short, string> ReservedNSTable;

		internal static Dictionary<short, string> ReservedPrefixTable;

		internal static Dictionary<short, string> ReservedNSPrefixTable;

		internal static readonly string nameXML;

		internal static readonly string nameXSLPI;

		internal static readonly string nameXMLSpace;

		internal static readonly string nameXMLLang;

		internal static readonly string nameNamespace;

		internal static readonly string nameXMLNamespace;

		internal static readonly string DEFAULT_PREFIX;

		internal static readonly string nameXMLNSNamespace;

		internal static readonly string nameDOCUMENTFRAGMENT;

		internal static readonly string nameDOCUMENT;

		internal static readonly string nameTEXT;

		internal static readonly string nameCOMMENT;

		internal static readonly string nameCDATA;

		internal static readonly string XMLSCHEMA;

		protected ObxmlDecodeRequest RequestObject
		{
			get
			{
				if (m_DecodeState != null)
				{
					return m_DecodeState.m_RequestObject;
				}
				return null;
			}
		}

		private ObxmlInstructionState CurrentInstruction => m_DecodeState.m_CurrentInstruction;

		private ObxmlStream DataStream
		{
			get
			{
				if (m_DecodeState == null)
				{
					return null;
				}
				return m_DecodeState.m_BinXmlStream;
			}
			set
			{
				if (m_DecodeState != null)
				{
					m_DecodeState.m_BinXmlStream = value;
					return;
				}
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.DecodeStateInvalid));
			}
		}

		internal ObxmlDecodeState DecodeState => m_DecodeState;

		internal ObxmlDecodeContext DecodeContext => this;

		static ObxmlDecoder()
		{
			ReservedNSTable = null;
			ReservedPrefixTable = null;
			ReservedNSPrefixTable = null;
			nameXML = "xml";
			nameXSLPI = "xml-stylesheet";
			nameXMLSpace = "xml:space";
			nameXMLLang = "xml:lang";
			nameNamespace = "xmlns";
			nameXMLNamespace = "http://www.w3.org/XML/1998/namespace";
			DEFAULT_PREFIX = "#default";
			nameXMLNSNamespace = "http://www.w3.org/2000/xmlns/";
			nameDOCUMENTFRAGMENT = "#document-fragment";
			nameDOCUMENT = "#document";
			nameTEXT = "#text";
			nameCOMMENT = "#comment";
			nameCDATA = "#cdata-section";
			XMLSCHEMA = "http://www.w3.org/2001/XMLSchema";
			ReservedPrefixTable = new Dictionary<short, string>();
			ReservedPrefixTable[1] = "xml";
			ReservedPrefixTable[2] = "xmlns";
			ReservedPrefixTable[3] = "xsi";
			ReservedPrefixTable[4] = "xsd";
			ReservedPrefixTable[5] = "xs";
			ReservedPrefixTable[6] = "csx";
			ReservedNSTable = new Dictionary<short, string>();
			ReservedNSTable[1] = "http://www.w3.org/XML/1998/namespace";
			ReservedNSTable[2] = "http://www.w3.org/XML/2000/xmlns/";
			ReservedNSTable[3] = "http://www.w3.org/2001/XMLSchema-instance";
			ReservedNSTable[4] = "http://www.w3.org/2001/XMLSchema";
			ReservedNSTable[5] = "http://xmlns.oracle.com/2004/csx";
			ReservedNSTable[6] = "http://xmlns.oracle.com/xdb";
			ReservedNSTable[7] = null;
			ReservedNSPrefixTable = new Dictionary<short, string>();
			ReservedNSPrefixTable[1] = "xml";
			ReservedNSPrefixTable[2] = "xmlns";
			ReservedNSPrefixTable[3] = "xsi";
			ReservedNSPrefixTable[4] = "xsd";
			ReservedNSPrefixTable[5] = "csx";
		}

		internal ObxmlDecoder(char[] encodedArray)
		{
			InitState();
		}

		internal ObxmlDecoder()
		{
			InitState();
		}

		private void InitState(bool resetting = false)
		{
			if (!resetting)
			{
				m_DecodeState = new ObxmlDecodeState();
			}
			m_DecodeState.SetObxmlDecodeState(this, null, null);
		}

		private bool IsDecoderValid()
		{
			if (base.IsValid && m_DecodeState != null && m_DecodeState.TokenMap != null)
			{
				return m_DecodeState.IsDecoderStateValid();
			}
			return false;
		}

		private bool InitRequestObject()
		{
			try
			{
				DataStream = new ObxmlStream(RequestObject.EncodedContent);
				m_IsDone = false;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.InitRequestObject, ex);
				throw;
			}
			return true;
		}

		internal PrefixInfo GetReservedPrefixInfo(short pfxid)
		{
			string prefix = null;
			if (ReservedPrefixTable.ContainsKey(pfxid))
			{
				prefix = ReservedPrefixTable[pfxid];
			}
			long num = 0L;
			return new PrefixInfo(nsid: pfxid switch
			{
				1 => 1uL, 
				2 => 2uL, 
				3 => 3uL, 
				4 => 4uL, 
				5 => 4uL, 
				6 => 5uL, 
				_ => throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenInvalidPrefix)), 
			}, decodeContext: DecodeContext, pfxid: pfxid, prefix: prefix);
		}

		internal void GetNextInstruction()
		{
			if (m_DecodeState == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.DecodeStateInvalid));
			}
			try
			{
				if (m_Instruction == null)
				{
					m_Instruction = new ObxmlInstruction(m_DecodeState);
				}
				else
				{
					m_Instruction.ResetObxmlInstruction(m_DecodeState);
				}
				m_Instruction.ReadInstructionInfo(readNewOpcode: true);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.GetNextInstruction, ex);
				throw;
			}
		}

		internal void SetDecodeComplete()
		{
			m_DecodeState.SetDecodeState(DecodeStates.SectionEnd, resetOldMasks: false);
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777728, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.SetDecodeComplete, "DECODE Completed Successfully..Exiting");
			}
			m_IsDone = true;
		}

		internal bool ResetRequestObject()
		{
			if (m_DecodeState != null && RequestObject != null)
			{
				RequestObject.ResetRequestObject();
				m_IsDone = false;
				return true;
			}
			return false;
		}

		internal override bool ResetDecodeState(bool disposing)
		{
			m_IsDone = true;
			if (disposing)
			{
				m_DecodeState.DisposeOutput();
			}
			Dispose();
			bool result = base.ResetDecodeState(disposing);
			if (!disposing)
			{
				InitState(resetting: true);
				m_Disposed = false;
			}
			return result;
		}

		internal ObxmlDecoder SetRequestObject(bool isFullDecode, long readOffset, byte[] inputBuffer, int inputLength, int writeOffset, byte[] outputBuffer, bool outputOwnedByClient, long textLengthRequested)
		{
			RequestObject.IsFullDecode = isFullDecode;
			RequestObject.TextLengthRequested = textLengthRequested;
			RequestObject.EncodedContent.ReadOffset = readOffset;
			RequestObject.EncodedContent.InputLength = inputLength;
			RequestObject.EncodedContent.SetObxmlContentObject(inputBuffer);
			RequestObject.m_RequestOutput.WriteOffset = writeOffset;
			RequestObject.m_RequestOutput.SetObxmlOutputObject(outputBuffer, outputOwnedByClient);
			InitRequestObject();
			return this;
		}

		internal ObxmlDecoder SetRequestObject(ref StringBuilder utf16OutPutBuilder, bool outputOwnedByClient, long readOffset, byte[] inputBuffer, int inputLength)
		{
			RequestObject.IsFullDecode = true;
			RequestObject.TextLengthRequested = long.MaxValue;
			RequestObject.EncodedContent.ReadOffset = readOffset;
			RequestObject.EncodedContent.InputLength = inputLength;
			RequestObject.EncodedContent.SetObxmlContentObject(inputBuffer);
			RequestObject.m_RequestOutput.SetObxmlOutputObject(ref utf16OutPutBuilder, outputOwnedByClient, inputLength);
			InitRequestObject();
			return this;
		}

		internal ObxmlDecoder SetRequestObject(bool isFullDecode, long readOffset, OracleBlob blob, int writeOffset, byte[] outputBuffer, bool outputOwnedByClient, long textLengthRequested)
		{
			RequestObject.IsFullDecode = isFullDecode;
			RequestObject.TextLengthRequested = textLengthRequested;
			RequestObject.EncodedContent.ReadOffset = readOffset;
			RequestObject.EncodedContent.InputLength = -1L;
			RequestObject.EncodedContent.SetObxmlContentObject(blob);
			RequestObject.m_RequestOutput.WriteOffset = writeOffset;
			RequestObject.m_RequestOutput.SetObxmlOutputObject(outputBuffer, outputOwnedByClient);
			InitRequestObject();
			return this;
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!m_Disposed)
			{
				if (disposing)
				{
					m_Instruction = null;
					m_DecodeState.ClearStateObject();
				}
				m_Disposed = true;
			}
		}

		internal ObxmlDecodeResponse Decode()
		{
			return Decode_New(RequestObject);
		}

		internal ObxmlDecodeResponse Decode_New(ObxmlDecodeRequest request)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777472, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.Decode_New, "DECODE START context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: true) + " CacheSize " + base.CacheSizeString + base.PerformanceCounterString);
			}
			try
			{
				ObxmlDecodeResponse lastDecodeResult = m_DecodeState.LastDecodeResult;
				if (!IsDecoderValid())
				{
					lastDecodeResult.ErrorType = ObxmlErrorTypes.InvalidArguments;
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.Decode_New, "DECODE Request Invalid");
					}
					return lastDecodeResult;
				}
				_ = request.m_RequestOutput;
				if ((int)request.TextLengthRequested != -1 && !request.IsFullDecode)
				{
					request.m_CountRemaining = request.TextLengthRequested;
				}
				else if (request.IsFullDecode)
				{
					request.m_CountRemaining = request.TextLengthRequested;
				}
				else
				{
					request.m_CountRemaining = DefaultDecodeBufferLength;
				}
				while (request.m_CountRemaining > 0 && !m_IsDone)
				{
					if (m_Instruction == null || !m_Instruction.InstructionPending)
					{
						GetNextInstruction();
					}
					if (m_Instruction.DecodeInstruction_New() && request.m_CountRemaining <= 0)
					{
						break;
					}
				}
				HandleDecodeComplete_New();
				return lastDecodeResult;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.Decode_New, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777728, OracleTraceClassName.ObxmlDecoder, OracleTraceFuncName.Decode_New, "DECODE Done/Exiting  context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: false) + " CacheSize " + base.CacheSizeString + base.PerformanceCounterString + " Duration " + base.DecodeTimeStamp);
				}
			}
		}

		private int HandleDecodeComplete_New()
		{
			byte[] outputBuffer = null;
			ObxmlOutputObject requestOutput = RequestObject.m_RequestOutput;
			if (requestOutput.IsOutputType(InputOutputTypes.ByteArray))
			{
				outputBuffer = (byte[])requestOutput.m_OutputObject;
			}
			ObxmlDecodeResponse lastDecodeResult = m_DecodeState.LastDecodeResult;
			lastDecodeResult.DecodedTextLength = RequestObject.TextLengthRequested - RequestObject.m_CountRemaining;
			lastDecodeResult.OutputBuffer = outputBuffer;
			lastDecodeResult.CurrentOffset = m_DecodeState.m_BinXmlStream.Position;
			if (m_IsDone)
			{
				lastDecodeResult.ErrorType = ObxmlErrorTypes.Done;
			}
			return (int)lastDecodeResult.DecodedTextLength;
		}
	}
}
